
#include "v7r.h"
#include "typedef.h"
// #include "astralapi.h"

static executable arch_exe_ttimer;
static executable arch_exe_tsched;
static executable arch_irq_handler;

void arch_enable_int(int id, int cpu)
{
    gic_enable_interrupt(id, cpu);
}


void arch_set_irq_handler(executable handler)
{
    arch_irq_handler = handler;
}


/**
 * @brief Set the tick scheduler object
 *
 * @param sched_func the tick schedule function
 */
void arch_set_tick_sched(executable sched_func)
{
	arch_exe_tsched = sched_func;
}

void arch_set_ttimer_timeout(executable do_timeout)
{
    arch_exe_ttimer = do_timeout;
}


/**
 * @brief This function is called by irq_handler
 * 
 * @param id the interrupt id
 */
void do_irq_handle(int id)
{
    switch (id)
    {
    case 0:
        if (arch_exe_tsched)
        {
            arch_exe_tsched(NULL);
        }
        break;
    case 29:
        gic_send_ici(0, 0x0, 0b01); // send all except self
        if(arch_exe_ttimer)
        {
            arch_exe_ttimer(NULL);
        }
        if (arch_exe_tsched)
        {
            arch_exe_tsched(NULL);
        }
        clean_private_timer_int_status();
        break;
    default:
        if (arch_irq_handler)
        {
            arch_irq_handler(CAST_AS(object, id));
        }
        break;
    }
}

void other_exception_handle(int type)
{
    switch (type)
    {
    case 1:
        kerror("unable to handle exception %s\n", "reset");
        break;
    case 2:
        kerror("unable to handle exception %s\n", "undef");
        break;
    case 3:
        kerror("unable to handle exception %s\n", "svc");
        break;
    case 4:
        kerror("unable to handle exception %s\n", "prefetch");
        break;
    case 5:
        kerror("unable to handle exception %s\n", "data");
        break;
    case 6:
        kerror("unable to handle exception %s\n", "fiq");
        break;

    default:
        kerror("unable to handle exception %s\n", "??");
        break;
    }
    while(1)
    {
    }
}

void arch_init()
{
    int arch_get_cpuid();
    int core_id = arch_get_cpuid();
    if (core_id == 0)
    {
        copy_vector();

        gicc_init();
        gicd_init();

        arch_enable_int(29, 0);

        private_timer_init();
        set_private_timer_period(0x80000U, 0x2u);
    }
    else
    {
        copy_vector();
        gicc_init();
        arch_enable_int(0, 0);
    }
}

word arch_disable_local_irq()
{
    word status = 0;
    asm volatile(" mrs     r0, cpsr\n\t"
                 "cpsid if\n\t" : "=r"(status) :);
    return status & 0b11000000;
}

void arch_enable_local_irq(word status)
{
    switch (status & 0b11000000)
    {
    case 0x40:
        // fiq disabled
        asm volatile("cpsie i");
        break;
    case 0x80:
        // irq disabled
        asm volatile("cpsie f");
        break;
    case 0x0:
        asm volatile("cpsie if");
    default:
        break;
    }
}